<!DOCTYPE html>
<html lang="zh-cn">
  <head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="author" content="Zhou Wei <zromyk@163.com>">
  <title>VScode调试、Makefile和CMake编译 C/C++</title>
  <link rel="shortcut icon" href="/favicon.ico">
  <link rel="stylesheet" href="/style/html/pure.css">
  <link rel="stylesheet" href="/style/html/main.css">
  <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.css">
  <!-- <link rel="stylesheet" href="https://apps.bdimg.com/libs/highlight.js/9.1.0/styles/default.min.css"> -->
<link rel="stylesheet" href="/style/article/highlight/default.min.css">
<link rel="stylesheet" href="/style/article/pell-1.0.6/dist/pell.css">

</head>
<body>
  <div id="menu-background"></div>
  <div id="menu">
    <div class="pure-menu pure-menu-horizontal">
  <ul class="pure-menu-list block-middle">
    <li class="pure-menu-item">
  <a class="pure-menu-heading" href="/index.html">ZROMYK</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/index.html">主页</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/archive/index.html">归档</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/download/index.html">下载</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/feedback/index.html">反馈</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/about/index.html">关于我</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="https://github.com/zromyk"><i class="fa fa-github" style="font-size:32px"></i></a>
</li>

  </ul>
</div>

  </div>
  <div id="layout">
    <div class="content">
      <div id="nav">
    <div id="navigation" class="navigation">
  <ul class="pure-menu-list">
    <li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#g">一、g++ 使用方法</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#_1">常用方法：直接编译生成目标文件</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#1">1. 基本使用方法</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#2">2. 目标选项</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#3">3. 调试选项</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav5" onclick="animateByNav()" href="#4">4. 链接方式选项</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#_2">二、编译工具链</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#vscode">三、VScode 配置编译调试文件</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#_3">本项目架构</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#project-c_cpp_propertiesjson">Project 配置文件 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>c_cpp_properties.json</code></span></a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#tasksjson">任务配置文件 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>tasks.json</code></span></a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#launchjson">调试配置文件 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>launch.json</code></span></a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#makefile-cmake">三、使用 Makefile 和 CMake 编译</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#makefile">使用 Makefile 编译</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#cmake">使用 CMake 编译</a>
</li>

  </ul>
</div>

</div>
<div id="content-articles">
  <h1 id="VScode调试、Makefile和CMake编译 C/C++" class="content-subhead">VScode调试、Makefile和CMake编译 C/C++</h1>
  <p>
    <span>2021-03-23</span>
    <span><span class="post-category post-category-other">VScode</span></span>
    <button id="button-markdownEditor" class="pure-button" onclick="markdownEditor()">启用编辑</button>
    <button id="button-save" class="pure-button" onclick="save()">保存</button>
  </p>
  <div id="content-articles-markdownEditor" style="display: none;">
    <h1>编辑 power by pell</h1>
    <div id="editor" class="pell"></div>
    <div style="margin-top:20px;">
        <h3>Text output:</h3>
        <div id="text-output"></div>
    </div>
    <div style="margin-top:20px;">
        <h3>HTML output:</h3>
        <pre id="html-output"></pre>
    </div>
  </div>
  <div id="content-articles-markdown">
    <h2 id="g">一、g++ 使用方法</h2>
<blockquote class="content-quote">
<p>参考：https://cloud.tencent.com/developer/article/1394309</p>
</blockquote>
<h4 id="_1">常用方法：直接编译生成目标文件</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">g++ main.cpp -g -o main.out -I [include dir]
</code></span></code></pre>
<h5 id="1">1. 基本使用方法</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">g++ -E test.cpp -o test.i   # 预处理(Preprocessing) 预处理器 cpp      生成预处理后的.i文件
g++ -S test.i   -o test.s   # 编译  (Compilation)   编译器 cc1plus   生成汇编.s文件
g++ -c test.s   -o test.o   # 汇编  (Assembly)      汇编器 as        生成二进制.o文件
g++    test.o   -o test.out # 链接  (Linking)       链接器 ld        生成二进制.out可执行文件 
</code></span></code></pre>
<h5 id="2">2. 目标选项</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">-I [dir]            # 自定义头文件目录
-include [file]     # 包含某个头文件，例子用法: 
                    gcc hello.c -include /root/pianopan.h   
-I-                 # 就是取消前一个参数的功能，所以一般在 -I [dir] 之后使用   
-idirafter [dir]    # 在 -I 的目录里面查找失败，将到目录 dir 里面查找。
-iprefix [prefix], -iwithprefix [dir] # 一般一起使用，当-I的目录查找失败，会到prefix+dir下查找。
-L [dir]            # 编译的时候，指定搜索库的路径。
-l [library]        # 指定编译的时使用的库，例子用法: 
                    gcc -l curses hello.c # 使用curses库编译连接，生成程序。  
</code></span></code></pre>
<h5 id="3">3. 调试选项</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">-g          # 指示编译器，在编译时，产生调试信息。
-gstabs     # 此选项以stabs格式生成调试信息,但不包括gdb调试信息。 
-gstabs+    # 此选项以stabs格式声称调试信息,并且包含仅供gdb使用的额外调试信息.   
-ggdb       # 此选项将尽可能的生成gdb可以使用的调试信息。
-glevel     # 请求生成调试信息，同时用level指出需要多少信息，默认的level值是2。
</code></span></code></pre>
<h5 id="4">4. 链接方式选项</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">-static         # 此选项将禁止使用动态库。优点：程序运行不依赖于其他库。缺点：可执行文件比较大。
-shared         # 此选项将尽量使用动态库，为默认选项。优点：生成文件比较小。缺点：运行时需要系统提供动态库。
-symbolic       # 建立共享目标文件的时候，把引用绑定到全局符号上。对所有无法解析的引用作出警告（除非用连接选项，'-Xlinker -z -Xlinker defs'取代)。注：只有部分系统支持该选项。
-Wl,-Bstatic    # 告诉链接器ld只链接静态库，如果只存在动态链接库，则链接器报错。
-Wl,-Bdynamic   # 告诉链接器ld优先使用动态链接库，如果只存在静态链接库，则使用静态链接库。
</code></span></code></pre>
<h2 id="_2">二、编译工具链</h2>
<div class="pure-table-scrollable"><table class="pure-table pure-table-horizontal">
<thead>
<tr>
<th>工具链</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>as</td>
<td>GNU汇编器</td>
</tr>
<tr>
<td>ld</td>
<td>GNU链接器</td>
</tr>
<tr>
<td>addr2line</td>
<td>将地址转换为文件名和行号</td>
</tr>
<tr>
<td>ar</td>
<td>用于创建，修改和提取档案的实用程序；创建静态库</td>
</tr>
<tr>
<td>nm</td>
<td>列出目标文件中的符号</td>
</tr>
<tr>
<td>objcopy</td>
<td>复制并转换目标文件；格式转换，比如把一个图片转成.o文件</td>
</tr>
<tr>
<td>objdump</td>
<td>显示目标文件中的信息</td>
</tr>
<tr>
<td>readelf</td>
<td>显示来自任何ELF格式对象文件的信息</td>
</tr>
<tr>
<td>size</td>
<td>列出的对象或归档文件的部分的尺寸</td>
</tr>
<tr>
<td>strings</td>
<td>列出文件中的可打印字符串</td>
</tr>
<tr>
<td>strip</td>
<td>丢弃的符号</td>
</tr>
</tbody>
</table></div>
<h2 id="vscode">三、VScode 配置编译调试文件</h2>
<h4 id="_3">本项目架构</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">├── .vscode
│   ├── c_cpp_properties.json
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── include # 头文件存放目录
│   └── test.h
└── src # 源文件存放目录
    ├── test.cpp
    └── main.cpp
</code></span></code></pre>
<h4 id="project-c_cpp_propertiesjson">Project 配置文件 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>c_cpp_properties.json</code></span></h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-json">{
    &quot;configurations&quot;: [
        {
            &quot;name&quot;: &quot;calculator&quot;,
            &quot;includePath&quot;: [ // 添加的额外头文件路径
                &quot;${workspaceFolder}/**&quot; // 将本工程工作空间下的所有目录添加到头文件搜索路径中
            ],
            &quot;defines&quot;: [],
            &quot;macFrameworkPath&quot;: [ // mac 固件路径
                &quot;/System/Library/Frameworks&quot;,
                &quot;/Library/Frameworks&quot;
            ],
            &quot;compilerPath&quot;: &quot;/usr/bin/g++&quot;, // 编译器所在的文件路径
            &quot;cStandard&quot;: &quot;c11&quot;,
            &quot;cppStandard&quot;: &quot;c++11&quot;,
            &quot;intelliSenseMode&quot;: &quot;clang-x64&quot;,
            &quot;browse&quot;: {
                &quot;path&quot;: [],
                &quot;limitSymbolsToIncludedHeaders&quot;: true,
                &quot;databaseFilename&quot;: &quot;&quot;
            }
        }
    ],
    &quot;version&quot;: 4
}
</code></span></code></pre>
<h4 id="tasksjson">任务配置文件 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>tasks.json</code></span></h4>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>shift+command+B</code></span> 根据 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>tasks.json</code></span> 执行编译任务</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-json">{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    &quot;version&quot;: &quot;2.0.0&quot;,
    &quot;tasks&quot;: [{
        &quot;label&quot;: &quot;Build&quot;,   // 任务的名称
        &quot;type&quot;: &quot;shell&quot;,    // 任务的类型，有两种（shell/process），shell的意思相当于先打开shell再输入命令，process是直接运行命令
        &quot;command&quot;: &quot;g++&quot;,   // 实际执行的命令
        &quot;args&quot;: [           // 在这里可以设置一些需要的参数
            &quot;-g&quot;,           // C/C++调试必备参数，在编译时，产生调试信息
            &quot;${workspaceFolder}/src/*&quot;, // src 源文件夹下的所有文件 (.cpp)
            &quot;-o&quot;, 
            &quot;${workspaceFolder}/main.out&quot;, // 生成的目标文件的存放路径和名称
            &quot;-I&quot;,
            &quot;${workspaceFolder}/include&quot; // 头文件存放路径 ...
        ],
        &quot;group&quot;: {
            &quot;kind&quot;: &quot;build&quot;,
            &quot;isDefault&quot;: true
        }
    }]
}
</code></span></code></pre>
<h4 id="launchjson">调试配置文件 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>launch.json</code></span></h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-json">{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    &quot;version&quot;: &quot;0.2.0&quot;,
    &quot;configurations&quot;: [
        {
            &quot;name&quot;: &quot;(lldb) Launch&quot;,    // 配置名称，将会在启动配置的下拉菜单中显示
            &quot;type&quot;: &quot;cppdbg&quot;,           // 配置类型
            &quot;request&quot;: &quot;launch&quot;,        // 请求配置类型，可以为launch（启动）或attach（附加）
            &quot;program&quot;: &quot;${workspaceFolder}/main.out&quot;, // 进行调试的程序的路径
            &quot;args&quot;: [], 
            &quot;stopAtEntry&quot;: true,        // 若设置为true时程序将暂停在程序入口处
            &quot;cwd&quot;: &quot;${workspaceFolder}&quot;,  // 当前调试所在目录
            &quot;environment&quot;: [],
            &quot;externalConsole&quot;: true,    // 调试时是否显示控制台窗口，设置为true即是显示控制台
            &quot;MIMode&quot;: &quot;lldb&quot;,
        }
    ]
}
</code></span></code></pre>
<h2 id="makefile-cmake">三、使用 Makefile 和 CMake 编译</h2>
<h4 id="makefile">使用 Makefile 编译</h4>
<p>项目框架</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">.
├── README.md
├── make.sh
├── makefile
└── src
    ├── test.c
    ├── test.h
    └── main.c
</code></span></code></pre>
<p>将<span style="overflow-x: auto; max-width:100%; display:inline;"><code>make.sh</code></span> 设置成可执行文件，双击可以快速打开终端编译本项目。</p>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>make.sh</code></span> 文件内容：</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">#!/bin/bash
cd `dirname $0`;
make;
</code></span></code></pre>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>makefile</code></span> 文件内容：</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell"># FlieName : makeflie
# Created by Wei Zhou on 2019/10/7
# Copyright © 2017 Muyiro. All rights reserved.

# Executable file name.
TARGET = binary_indexed_tree_example
# Source directory address.
DIR_SRC = ./src
# Object directory address.
DIR_OBJ = ./obj

# Compile file type: cpp / c ...
# EXTENSION = cpp
EXTENSION = c
# The compiler: g++ / gcc ...
# CC = g++ -std=c++11
CC = gcc

# *** Don't modify!!! ***

# Gets the source file address
# 正则表达式表示目录下所有.c文件
SRC = $(wildcard $(DIR_SRC)/*.$(EXTENSION))
# Gets the object file address,
# OBJ 表示 SRC 中把列表中的 .c 全部替换为 .o
OBJ = $(patsubst %.$(EXTENSION), $(DIR_OBJ)/%.o, $(notdir $(SRC)))

# Generate the executable.
$(TARGET): clean MKDIR_OBJ $(OBJ)
    $(CC) $(OBJ) -o $(TARGET)
    $(CC) $(OBJ) -o $(DIR_OBJ)/$(TARGET).out

# Creat a object directory.
MKDIR_OBJ:
    mkdir -p $(DIR_OBJ)

# Compile all source files.
# $@表示目标文件, $^表示所有依赖文件, $&lt;表示第一个依赖文件
$(DIR_OBJ)/%.o: $(DIR_SRC)/%.$(EXTENSION)
    $(CC) -c $&lt; -o $@

# View the source file that will compile
.PHONY: source
source:
    @echo $(SRC)
    @echo $(OBJ)
    @echo $(CC) $(OBJ) -o $(TARGET)

# Clean target file, object files and its directory.
.PHONY: clean
clean:
    rm -rf $(DIR_OBJ) $(TARGET)

# Clean object files and its directory.
.PHONY: clean_obj
clean_obj:
    rm -rf $$(DIR_OBJ)

</code></span></code></pre>
<h4 id="cmake">使用 CMake 编译</h4>
<p>项目框架</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">.
├── CMakeLists.txt
├── README.md
├── build.sh
├── include
│   └── test.h
└── src
    ├── test.cpp
    └── main.cpp
</code></span></code></pre>
<p>将 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>build.sh</code></span> 设置成可执行文件，双击可以快速打开终端编译本项目。</p>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>build.sh</code></span> 文件内容：</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">#!/bin/bash
project_path=$(cd `dirname $0`; pwd);
project_name=&quot;${project_path##*/}&quot;;
echo $project_path;
echo $project_name;
cd `dirname $0`;
echo &quot;mkdir -p build &amp; cd build&quot;;
mkdir -p build;
cd build;
echo &quot;cmake .. &amp; make&quot;;
cmake ..;
make;
</code></span></code></pre>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>CMakeLists.txt</code></span> 文件内容：</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">#Cmake verson
cmake_minimum_required(VERSION 3.7)

#Project name
project(test)

#Add search paths for multiple specified header files, separated by Spaces, to the project.
include_directories(include)

#Stores all source files in the specified directory in a single variable.
aux_source_directory(src SRC_LIST)
#The final elf file to be generated is called XXX, and the source file is XXX.
add_executable(main ${SRC_LIST})

#EXECUTABLE_OUTPUT_PATH: the location of the target binary executable.
#PROJECT_SOURCE_DIR: the root directory of the project.
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
</code></span></code></pre>
  </div>
</div>
 
    </div>
  </div>
  <div id="footer-background">
    <div id="footer">
      <div class="legal pure-g">
  <div class="pure-u-1 u-sm-1-2">
    <p class="legal-license"><a href="https://beian.miit.gov.cn/#/Integrated/index">浙ICP备2020038748号</a></p>
  </div>
  <div class="pure-u-1 u-sm-1-2">
    <p class="legal-links"><a href="https://github.com/zromyk">GitHub</a></p>
    <p class="legal-copyright">Copyright © 2021 Wei Zhou. 保留所有权利。</p>
  </div>
</div>
    </div>
  </div>
  <!-- <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> -->
  <script src="/style/html/jquery.min.js"></script>
  <script src='/style/article/latex/latest.js?config=TeX-MML-AM_CHTML'></script>
<!-- <script src="https://cdn.geogebra.org/apps/deployggb.js"></script> -->
<script src="/style/article/deployggb.js"></script>
<!-- <script src="https://apps.bdimg.com/libs/highlight.js/9.1.0/highlight.min.js"></script> -->
<script type="text/javascript">
  // 脚本：navigation 随鼠标移动自动变换宽度
  var element = document.getElementById("navigation"); // 获取要操作的元素
  var elementWidth = parseInt(getComputedStyle(element).width);
  var elementLeft = 0;
  var elementRight = 0;
  element.addEventListener('mouseenter', function (event) { // 添加鼠标按下事件的监听器
    elementLeft = element.getBoundingClientRect().left - 10;
    elementRight = element.getBoundingClientRect().left + elementWidth * 3;
    window.addEventListener('mousemove', resize); // 添加全局的鼠标移动事件的监听器
  });

  function resize(event) {
    var minWidth = elementWidth;
    var maxWidth = elementWidth * 2.5;
    // console.log(elementLeft, event.clientX, elementRight, event.clientX - elementLeft + elementWidth / 2);
    if (elementLeft <= event.clientX && event.clientX <= elementRight) {
      var width = event.clientX - elementLeft + elementWidth / 2;
      width = Math.min(width, maxWidth);
      width = Math.max(width, minWidth);
      element.style.width = width + 'px'; // 设置新的宽度样式属性
    }
    else {
      element.style.width = elementWidth + 'px'; // 设置新的宽度样式属性
      stopResize();
    }
  }

  function stopResize() {
    element.style.width = elementWidth + 'px'; // 设置新的宽度样式属性
    // console.log("stopResize", elementLeft, event.clientX, elementRight, event.clientX - elementLeft + elementWidth / 2);
    window.removeEventListener('mousemove', resize); // 移除鼠标移动事件的监听器
  }
</script>
<script src="/style/article/highlight/highlight.min.js"></script>
<script type="text/javascript">
  // 脚本：code语法高亮
  hljs.initHighlightingOnLoad();
</script>
<script>
  function animateByNav() {
    $("html").animate({
        scrollTop: ($(event.target.hash).offset().top - 52)
    }, 300);
  };
</script>
<script src="/style/article/pell-1.0.6/dist/pell.js"></script>
<script>
  // 脚本：自由编辑页面
  var editor = window.pell.init({
    element: document.getElementById('editor'),
    defaultParagraphSeparator: 'p',
    onChange: function(html) {
        document.getElementById('text-output').innerHTML = html
        document.getElementById('html-output').textContent = html
    }
  });

  function markdownEditor() {
    var articles = document.getElementById('content-articles-markdown');
    if (articles.getAttribute("contenteditable") == "true") {
        articles.setAttribute("contenteditable", "false");
        document.getElementById("content-articles-markdownEditor").style.display = "none"; //隐藏
        document.getElementById("button-markdownEditor").innerHTML = "启用编辑";
    } else {
        articles.setAttribute("contenteditable", "true");
        document.getElementById("content-articles-markdownEditor").style.display = ""; //显示
        document.getElementById("button-markdownEditor").innerHTML = "关闭编辑";
    }
  };

  function save() {
      window.alert("保存成功");
  };
</script>

</body>
</html>
